﻿/*
 * Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see license.txt or http://cksource.com/ckfinder/license
 *
 * The software, this file and its contents are subject to the CKFinder
 * License. Please read the license.txt file before using, installing, copying,
 * modifying or distribute this file or part of its contents. The contents of
 * this file is part of the Source Code of CKFinder.
 */

CKFinder.addPlugin( 'fileeditor', function( api )
{
    var regexTextExt = /^(ascx|asp|aspx|c|cfc|cfm|cpp|cs|css|htm|html|inc|java|js|less|md|mysql|php|pl|py|rb|rst|sass|scss|sql|txt|xml|xsl|xslt)$/i,
        regexCodeMirrorExt = /^(ascx|asp|aspx|c|cfc|cfm|cpp|cs|css|htm|html|java|js|less|md|mysql|php|pl|py|rb|rst|sass|scss|sql|xml|xsl)$/i,
        codemirror,
        file,
        fileLoaded = false,
        doc,

        codeMirrorPath = CKFinder.getPluginPath( 'fileeditor' ) + 'codemirror/',
        codeMirrorModePath = codeMirrorPath + 'mode/',

        codeMirrorParsers = {
        c: codeMirrorModePath + 'clike/clike.js',
        css: codeMirrorModePath + 'css/css.js',
        html: [ codeMirrorModePath + 'xml/xml.js', codeMirrorModePath + 'javascript/javascript.js', codeMirrorModePath + 'css/css.js', codeMirrorModePath + 'htmlmixed/htmlmixed.js' ],
        js: codeMirrorModePath + 'javascript/javascript.js',
        md: codeMirrorModePath + 'markdown/markdown.js',
        php: [ codeMirrorModePath + 'xml/xml.js', codeMirrorModePath + 'javascript/javascript.js', codeMirrorModePath + 'css/css.js', codeMirrorModePath + 'clike/clike.js', codeMirrorModePath + 'php/php.js' ],
        pl: codeMirrorModePath + 'perl/perl.js',
        py: codeMirrorModePath + 'python/python.js',
        rb: codeMirrorModePath + 'ruby/ruby.js',
        rst: [ codeMirrorModePath + 'rst/rst.js', codeMirrorModePath + 'python/python.js', codeMirrorModePath + 'stex/stex.js', codeMirrorPath + 'addon/mode/overlay.js' ],
        sql: codeMirrorModePath + 'sql/sql.js',
        sass: codeMirrorModePath + 'sass/sass.js',
        xml: codeMirrorModePath + 'xml/xml.js'
    };
    codeMirrorParsers.ascx = codeMirrorParsers.html;
    codeMirrorParsers.asp = codeMirrorParsers.html;
    codeMirrorParsers.aspx = codeMirrorParsers.html;
    codeMirrorParsers.cfm = codeMirrorParsers.html;
    codeMirrorParsers.cfc = codeMirrorParsers.html;
    codeMirrorParsers.less = codeMirrorParsers.css;
    codeMirrorParsers.cpp = codeMirrorParsers.c;
    codeMirrorParsers.cs = codeMirrorParsers.c;
    codeMirrorParsers.htm = codeMirrorParsers.html;
    codeMirrorParsers.java = codeMirrorParsers.c;
    codeMirrorParsers.mysql = codeMirrorParsers.sql;
    codeMirrorParsers.scss = codeMirrorParsers.css;
    codeMirrorParsers.xsl = codeMirrorParsers.xml;

    var codeMirrorModes = {
        ascx : 'htmlmixed',
        asp : 'htmlmixed',
        aspx : 'htmlmixed',
        c : 'clike',
        cpp : 'clike',
        cs : 'clike',
        cfc : 'htmlmixed',
        cfm : 'htmlmixed',
        htm : 'htmlmixed',
        html : 'htmlmixed',
        java : 'clike',
        js : 'javascript',
        less : 'css',
        md : 'markdown',
        mysql : 'sql',
        php : 'php',
        pl : 'perl',
        py : 'python',
        rb : 'ruby',
        rst : 'rst',
        sass : 'sass',
        scss : 'css',
        sql : 'sql',
        xsl : 'xml'
    };

    CKFinder.dialog.add( 'fileEditor', function( api )
    {
        var height, width,
            saveButton = (function()
                {
                    return {
                        id : 'save',
                        label : api.lang.Fileeditor.save,
                        type : 'button',
                        onClick : function ( evt )
                        {
                            if ( !fileLoaded )
                                return true;

                            var dialog = evt.data.dialog,
                                content = codemirror ? codemirror.getValue() : doc.getById( 'fileContent' ).getValue();
                            api.connector.sendCommandPost( 'SaveFile', null, {
                                    content : content,
                                    fileName : file.name
                                },
                                function( xml )
                                {
                                    if ( xml.checkError() )
                                        return false;

                                    api.openMsgDialog( '', api.lang.Fileeditor.fileSaveSuccess );
                                    dialog.hide();
                                    return undefined;
                                },
                                file.folder.type,
                                file.folder
                            );
                            return false;
                        }
                    };
                })();

        if ( api.inPopup )
        {
            width = api.document.documentElement.offsetWidth;
            height = api.document.documentElement.offsetHeight;
        }
        else
        {
            var parentWindow = ( api.document.parentWindow || api.document.defaultView ).parent;
            width = parentWindow.innerWidth ? parentWindow.innerWidth : parentWindow.document.documentElement.clientWidth;
            height = parentWindow.innerHeight ? parentWindow.innerHeight : parentWindow.document.documentElement.clientHeight;
        }

        var cssWidth = parseInt( parseInt( width, 10 ) * 0.6 ),
            cssHeight = parseInt( parseInt( height, 10 ) * 0.7 - 20 );

        return {
            title : api.getSelectedFile().name,
            minWidth : parseInt( parseInt( width, 10 ) * 0.6 ),
            minHeight : parseInt( parseInt( height, 10 ) * 0.7 ),
            onHide : function()
            {
                if ( fileLoaded )
                {
                    var fileContent = doc.getById( 'fileContent' );
                    if ( fileContent )
                        fileContent.remove();
                }
            },
            onShow : function()
            {
                var dialog = this;

                doc = dialog.getElement().getDocument();
                var win = doc.getWindow();
                doc.getById( 'fileArea' ).setHtml( '<div class="ckfinder_loader_32" style="margin: 100px auto 0 auto;text-align:center;"><p style="height:' + cssHeight + 'px;width:' + cssWidth + 'px;">' + api.lang.Fileeditor.loadingFile + '</p></div>' );

                file = api.getSelectedFile();
                var enableCodeMirror = regexCodeMirrorExt.test( file.ext );
                this.setTitle( file.name );

                if ( enableCodeMirror && win.$.CodeMirror === undefined ) {
                    doc.appendStyleSheet( codeMirrorPath + 'lib/codemirror.css' );
                }

                // If CKFinder is running under a different domain than baseUrl, then the following call will fail:
                // CKFinder.ajax.load( file.getUrl() + '?t=' + (new Date().getTime()), function( data )...

                var url = api.connector.composeUrl( 'DownloadFile', { FileName : file.name, format : 'text', t : new Date().getTime() },
                        file.folder.type, file.folder );

                CKFinder.ajax.load( url, function( data )
                {
                    if ( data === null || ( file.size > 0 && data === '' ) )
                    {
                        api.openMsgDialog( '', api.lang.Fileeditor.fileOpenError );
                        dialog.hide();
                        return;
                    }
                    else
                        fileLoaded = true;

                    var fileArea = doc.getById( 'fileArea' );

                    fileArea.setStyle( 'height', '100%' );
                    fileArea.setHtml( '<textarea id="fileContent" style="height:' + cssHeight + 'px; width:' + cssWidth + 'px"></textarea>' );

                    var fileContent = doc.getById( 'fileContent' );
                    if ( CKFinder.env.chrome || CKFinder.env.opera ) {
                        fileContent.setHtml( CKFinder.tools.htmlEncode( data ) );
                    } else {
                        fileContent.setText( data );
                    }

                    codemirror = null;
                    if ( enableCodeMirror )
                    {
                        CKFinder.scriptLoader.load( codeMirrorPath + 'lib/codemirror.js', function()
                        {
                            CKFinder.scriptLoader.load( codeMirrorParsers[ file.ext ], function()
                            {
                                codemirror = win.$.CodeMirror.fromTextArea( doc.getById( 'fileContent' ).$, { mode : codeMirrorModes[ file.ext ] || file.ext } );
                                var fileArea = doc.getById( 'fileArea' );

                                // TODO get rid of ugly buttons and provide something better
                                var undoB = doc.createElement( 'button', { attributes: { 'label' : api.lang.common.undo, 'class' : 'fileeditor-button' } } );
                                undoB.on( 'click', function()
                                {
                                    codemirror.undo();
                                });
                                undoB.setHtml( api.lang.common.undo );
                                undoB.appendTo( fileArea );

                                var redoB = doc.createElement( 'button', { attributes: { 'label' : api.lang.common.redo, 'class' : 'fileeditor-button' } } );
                                redoB.on( 'click', function()
                                {
                                    codemirror.redo();
                                });
                                redoB.setHtml( api.lang.common.redo );
                                redoB.appendTo( fileArea );
                            }, this, false, doc.getHead(), doc );
                        }, this, false, doc.getHead(), doc );
                    }
                });
            },
            contents : [
                {
                    id : 'tab1',
                    label : '',
                    title : '',
                    expand : true,
                    padding : 0,
                    elements :
                    [
                        {
                            type : 'html',
                            id : 'htmlLoader',
                            html : '' +
                            '<style type="text/css">' +
                            '#fileArea .CodeMirror {background:white;height: '+ cssHeight +'px;}' +
                            '#fileArea .CodeMirror-scroll {height:' + cssHeight + 'px; width:' + cssWidth + 'px;margin-bottom:0;}' +
                            '#fileArea .CodeMirror .cm-tab {white-space:pre;}' +
                            'button.fileeditor-button {border: 1px solid #999;margin: 7px 7px 0 0;text-align: center;width: 60px;color: #222;padding: 3px 10px;}' +
                            // override .cke-compatibility issues which resolves to cursor below edited content bug
                            '#fileArea .CodeMirror * {font-family:monospace !important;white-space:pre !important;line-height: 1.2em;}' +
                            // FF >= 12 has some scrolling issue
                            ( CKFinder.env.gecko && CKFinder.env.version >= 120000 ? '#fileArea .CodeMirror-scroll > div > div {position:absolute !important}' : '' ) +
                            '</style>' +
                            '<div id="fileArea"></div>'
                        }
                    ]
                }
            ],
            // TODO http://dev.fckeditor.net/ticket/4750
            buttons : [ saveButton, CKFinder.dialog.cancelButton ]
        };
    } );

    api.addFileContextMenuOption( { label : api.lang.Fileeditor.contextMenuName, command : 'fileEditor' } , function( api, file )
            {
                api.openDialog( 'fileEditor' );
            },
            function ( file )
            {
                var maxSize = 1024;

                if ( typeof ( CKFinder.config.fileeditorMaxSize ) != 'undefined' )
                    maxSize = CKFinder.config.fileeditorMaxSize;

                // Disable for images, binary files, large files etc.
                if ( regexTextExt.test( file.ext ) && file.size <= maxSize )
                    return file.folder.acl.fileDelete ? true : -1;

                return false;
            });
} );
